package com.tianji.learning.service.impl;

import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author root
 * @since 2023-10-23
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    private final ILearningLessonService lessonService;

    private final CourseClient courseClient;

    private final LearningRecordDelayTaskHandler taskHandler;

    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        // 1. 获取当前登录用户
        Long userId = UserContext.getUser();
        // 2. 查询课表信息，条件 user_id 和 courseId
        LearningLesson lesson = lessonService.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        if(lesson == null){
            throw new BizIllegalException("该课程未加入课表");
        }
        // 3. 查询学习记录，条件lesson_id 和 userId
        List<LearningRecord> recordList = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, lesson.getId())
                .eq(LearningRecord::getUserId, userId)
                .list();
        // 4. 封装结果返回
        LearningLessonDTO dto = new LearningLessonDTO();
        dto.setId(lesson.getId()); //课表 id
        dto.setLatestSectionId(lesson.getLatestSectionId()); // 最近学习的小节 id
        List<LearningRecordDTO> dtoList = BeanUtils.copyList(recordList, LearningRecordDTO.class);
        dto.setRecords(dtoList);


        return dto;
    }

    @Override
    public void addLearningRecord(LearningRecordFormDTO dto) {
        // 1. 获取当前登录用户
        Long userId = UserContext.getUser();
        // 2. 处理学习记录
        boolean isFinished = false;//代表本小节是否已学完
        if (dto.getSectionType().equals(SectionType.VIDEO)) {
            // 2.1 提交视频播放记录
            isFinished = handleVideoRecord(userId, dto);
        }else {
            // 2.2 提交考试记录
            isFinished = handleExamRecord(userId, dto);
        }
        // 3. 处理课表数据
        // 如果本小节是第一次学完就处理课表数据
        if(!isFinished){
            return;
        }
        handleLessonData(dto, true);
    }
    //处理课表相关数据
    private void handleLessonData(LearningRecordFormDTO dto, boolean isFinished) {
        // 1. 查询课表 learning_lesson  条件 lesson_id 主键
        LearningLesson lesson = lessonService.getById(dto.getLessonId());
        if(lesson == null){
            throw new BizIllegalException("课表不存在");
        }
        // 2. 判断是否是第一次学完 isFinished是否为 true
        boolean allFinished = false;// 所有小节是否学完
        if(isFinished){
            // 3. 远程调用课程服务，得到课程总小节数
            CourseFullInfoDTO cinfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
            if (cinfo == null){
                throw new BizIllegalException("课程不存在");
            }
            Integer sectionNum = cinfo.getSectionNum();//该课程的总小节数
            // 4. isFinished 为 true。判断用户是否学完了本课程的
            // 所有小节
            Integer learnedSections = lesson.getLearnedSections();
            allFinished = learnedSections + 1 >= sectionNum;
        }
        // 5. 更新课表数据
        lessonService.lambdaUpdate()
                .set(lesson.getStatus() == LessonStatus.NOT_BEGIN, LearningLesson::getStatus, LessonStatus.LEARNING)//如果之前还没有开始学习，就改为学习中
                .set(allFinished, LearningLesson::getStatus, LessonStatus.FINISHED)//所有小节都学完了就改为已学完
                .set(LearningLesson::getLatestSectionId, dto.getSectionId())
                .set(LearningLesson::getLatestLearnTime, dto.getCommitTime())
                //.set(isFinished,LearningLesson::getLearnedSections,lesson.getLearnedSections()+1)
                .setSql("learned_sections = learned_sections + 1")
                .eq(LearningLesson::getId, lesson.getId())
                .update();

    }

    // 处理视频播放记录
    private boolean handleVideoRecord(Long userId, LearningRecordFormDTO dto) {
        // 1. 查询旧的学习记录 learning_record  条件： lessonId(userid + courseid) section_id
        LearningRecord learningRecord = queryOldRecord(dto.getLessonId(),dto.getSectionId());
//        LearningRecord learningRecord = this.lambdaQuery()
//                .eq(LearningRecord::getLessonId, dto.getLessonId())
//                .eq(LearningRecord::getSectionId, dto.getSectionId())
//                .one();
        // 2. 判断课程是否存在
        if(learningRecord == null){
            // 3. 不存在。新增学习记录
            LearningRecord record = BeanUtils.copyBean(dto,LearningRecord.class);
            record.setUserId(userId);
            // 保存学习记录 learning_record
            boolean result = this.save(record);
            //判断添加结果
            if(!result){
                throw new DbException("新增考试记录失败");
            }
            return false;
        }
        // 4. 存在。更新学习记录 learning_record 更新什么: moment
        // 判断本小节是否是第一次学完
        boolean isFinished = !learningRecord.getFinished() && dto.getMoment() * 2 >= dto.getDuration();
        if (!isFinished){
            LearningRecord record = new LearningRecord();
            record.setLessonId(dto.getLessonId());
            record.setSectionId(dto.getSectionId());
            record.setMoment(dto.getMoment());
            record.setFinished(learningRecord.getFinished());
            record.setId(learningRecord.getId());
            taskHandler.addLearningRecordTask(record);
            return false;
        }
        //根据 学习记录id 更改对应学习记录的 学习进度(moment) 如果是第一次学完就还需要添加 是否学完(finished) 和 学完时间(finishTime)
        boolean result = this.lambdaUpdate()
                .set(LearningRecord::getMoment, dto.getMoment())
                .set(LearningRecord::getFinished, true)
                .set(LearningRecord::getFinishTime, dto.getCommitTime())
                .eq(LearningRecord::getId, learningRecord.getId())
                .update();
        if(!result){
            throw new DbException("更新视频学习记录失败");
        }
        //清理 redis 缓存
        taskHandler.cleanRecordCache(dto.getLessonId(),dto.getSectionId());

        return true;
//        //再写一遍
//        // 1.  查询学习记录
//        LearningRecord section = this.lambdaQuery()
//                .eq(LearningRecord::getLessonId, dto.getLessonId())
//                .eq(LearningRecord::getSectionId, dto.getSectionId())
//                .one();
//        // 2. 判断是否存在
//        if(section == null){
//            // 3. 不存在，创建
//            LearningRecord record = BeanUtils.copyBean(dto, LearningRecord.class);
//            record.setUserId(userId);
//            boolean result = this.save(record);
//            if(!result){
//                throw new DbException("新增视频片段失败");
//            }
//            return false;
//        }
//        // 4. 存在，更新
//        // 判断是否第一次看完
//        boolean Finished = !section.getFinished() && dto.getMoment()*2 >= dto.getDuration();
//        boolean result = this.lambdaUpdate()
//                .eq(LearningRecord::getSectionId, section.getSectionId())
//                .set(LearningRecord::getMoment, dto.getMoment())
//                .set(Finished, LearningRecord::getFinished, true)
//                .set(Finished, LearningRecord::getFinishTime, dto.getCommitTime())
//                .update();
//        if(!result){
//            throw new DbException("更新视频片段失败");
//        }
//        return Finished;
    }

    private LearningRecord queryOldRecord(Long lessonId, Long sectionId) {
        // 1. 查询缓存
        LearningRecord cache = taskHandler.readRecordCache(lessonId, sectionId);
        // 2. 如果命中直接返回
        if (cache != null){
            return cache;
        }
        // 3. 未命中 查询db
        LearningRecord dbRecord = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, lessonId)
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
        if(dbRecord == null){
            return null;
        }
        // 4. 放入缓存
        taskHandler.writeRecordCache(dbRecord);
        return dbRecord;
    }


    // 处理考试记录
    private boolean handleExamRecord(Long userId, LearningRecordFormDTO dto) {
        // 1. 将 dto 转换为 po
        LearningRecord record = BeanUtils.copyBean(dto,LearningRecord.class);
        record.setUserId(userId);
        record.setFinished(true);//提交考试记录默认本小节已学完，无需判断直接赋值
        record.setFinishTime(dto.getCommitTime());//完成学习时间
        // 保存学习记录 learning_record
        boolean result = this.save(record);
        if(!result){
            throw new DbException("新增考试记录失败");
        }
        return true;
    }
}
